package com.example.demo.config;

import com.example.demo.auth.UserDetailsServiceImpl;
import com.example.demo.auth.compoent.*;
import com.example.demo.auth.service.DynPermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsUtils;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


//    @Autowired
//    @Qualifier("authUserDetailsServiceImpl")
//    UserDetailsService userDetailsService;

    @Autowired
    private MyOncePerRequestFilter myOncePerRequestFilter;
    @Autowired
    CustomLogoutSuccessHandler customLogoutSuccessHandler;

    @Autowired
    private CustomizeSessionInformationExpiredStrategy customizeSessionInformationExpiredStrategy;
    @Autowired
    MyAccessDenyHandler myAccessDenyHandler;

    @Autowired
    MyAuthenticationEntryPoint myAuthenticationEntryPoint;

    @Autowired
    CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

    @Autowired
    CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    @Autowired
    DynPermissionService dynPermissionService;
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        // 设置默认的加密方式（强hash方式加密）
        return new BCryptPasswordEncoder();
    }
    @Override
    @Bean
    public UserDetailsService userDetailsService(){
        return new UserDetailsServiceImpl();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //第1步：解决跨域问题。cors 预检请求放行,让Spring security 放行所有preflight request（cors 预检请求）
        http.authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll();

        //第2步：让Security永远不会创建HttpSession，它不会使用HttpSession来获取SecurityContext
        http.csrf().disable();
//                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
//                .and().headers().cacheControl();

        //限制最大登录人数,自定义人数过多的返回策略
        http.sessionManagement()
                .maximumSessions(1).expiredSessionStrategy(customizeSessionInformationExpiredStrategy);

        //首页登录才能访问
        http.authorizeRequests().antMatchers("/index").authenticated();

        //第4步：拦截账号、密码。覆盖 UsernamePasswordAuthenticationFilter过滤器,主要解决登录方面的问题
        http.addFilterAt(myUsernamePasswordAuthenticationFilter() , UsernamePasswordAuthenticationFilter.class);

        //第 5 配置用户的权限（这里最好动态获取用户权限）
        //测试权限，让有query_user权限的人才可以调用getUser接口
        http.authorizeRequests()
                .antMatchers("/login/**","/","/cap").permitAll()
                .anyRequest().access("@DynPermissionService.checkPermission(request,authentication)");
//                .antMatchers("/getUser").hasAuthority("query_user");



        //第6 处理非法请求（用户未登录，用户权限不足）
        //AuthenticationEntryPoint 用来解决匿名用户访问无权限资源时的异常
        //AccessDeineHandler 用来解决认证过的用户访问无权限资源时的异常
        http.exceptionHandling()
                .authenticationEntryPoint(myAuthenticationEntryPoint)
                .accessDeniedHandler(myAccessDenyHandler);

        //在用户名认证之前认证验证码
        http.addFilterBefore(myOncePerRequestFilter,UsernamePasswordAuthenticationFilter.class);

        //7 登录方式
        http.formLogin()
                .failureHandler(customAuthenticationFailureHandler)
                .successHandler(customAuthenticationSuccessHandler);
        // 第8步：退出操作
        http.logout()
                .permitAll()
                .logoutSuccessHandler(customLogoutSuccessHandler)
                .deleteCookies("JSESSIONID");

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService());
    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        //将项目中静态资源路径开放出来
        web.ignoring().antMatchers("/config/**", "/css/**", "/fonts/**", "/img/**", "/js/**");
    }

    /**
     * 手动注册账号、密码拦截器
     * @return
     * @throws Exception
     */
    @Bean
    MyUsernamePasswordAuthenticationFilter myUsernamePasswordAuthenticationFilter() throws Exception {
        MyUsernamePasswordAuthenticationFilter filter = new MyUsernamePasswordAuthenticationFilter();
        //成功后处理
        filter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler);
        //失败后处理
        filter.setAuthenticationFailureHandler(customAuthenticationFailureHandler);
        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }

}
